package io.github.talelin.latticy.service.oms.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.talelin.autoconfigure.exception.ForbiddenException;
import io.github.talelin.latticy.bo.FileBO;
import io.github.talelin.latticy.common.LocalUser;
import io.github.talelin.latticy.common.enums.ResponseEnum;
import io.github.talelin.latticy.common.pojo.BarCodeEntity;
import io.github.talelin.latticy.common.pojo.BaseDO;
import io.github.talelin.latticy.common.util.*;
import io.github.talelin.latticy.dto.oms.product.PrintBarcodeDTO;
import io.github.talelin.latticy.dto.oms.product.ProductDTO;
import io.github.talelin.latticy.dto.oms.product.ProductPage;
import io.github.talelin.latticy.execl.oms.Product.ProductExecl;
import io.github.talelin.latticy.feign.WmsCategoryFeignClient;
import io.github.talelin.latticy.mapper.oms.PortfolioProductsMapper;
import io.github.talelin.latticy.mapper.oms.ProductBarcodeMapper;
import io.github.talelin.latticy.mapper.oms.ProductMapper;
import io.github.talelin.latticy.mapper.oms.ProductShopMapper;
import io.github.talelin.latticy.model.oms.PortfolioProductsDO;
import io.github.talelin.latticy.model.oms.ProductBarcodeDO;
import io.github.talelin.latticy.model.oms.ProductShopDO;
import io.github.talelin.latticy.model.oms.ProductDO;
import io.github.talelin.latticy.service.FileService;
import io.github.talelin.latticy.service.oms.PortfolioProductsService;
import io.github.talelin.latticy.service.oms.ProductBarcodeService;
import io.github.talelin.latticy.service.oms.ProductService;
import io.github.talelin.latticy.service.oms.ProductShopService;
import io.github.talelin.latticy.vo.FindResultVO;
import io.github.talelin.latticy.vo.oms.CombinationProductVO;
import io.github.talelin.latticy.vo.oms.ProductVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * @ClassName：ProductServiceImpl
 * @Author: ljj
 * @Date: 2022/5/10 9:27
 */
@Service
@Slf4j
public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> implements ProductService {

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private FileService fileService;

    @Autowired
    private ProductShopService productShopService;

    @Autowired
    private ProductShopMapper productShopMapper;

    @Autowired
    private ProductBarcodeService productBarcodeService;

    @Autowired
    private ProductBarcodeMapper productBarcodeMapper;

    @Autowired
    private PortfolioProductsService portfolioProductsService;

    @Autowired
    private PortfolioProductsMapper portfolioProductsMapper;

    @Autowired
    private WmsCategoryFeignClient wmsCategoryFeignClient;

    @Transactional
    @Override
    public void add(ProductDTO productDTO) {
        // 检查sku
        Optional.ofNullable(productDTO.getSku()).ifPresent(this::checkSkuExist);
        // 检查fnsku
        Optional.ofNullable(productDTO.getProductBarcodes()).ifPresent(this::checkFnSkuExist);
        ProductDO productDO = BeanUtils.copyProperties(productDTO, ProductDO.class);
        productDO.setCreatorCode(LocalUser.getLocalUser().getUsername());
        if (CollectionUtils.isNotEmpty(productDTO.getPortfolioProducts())) {
            productDO.setType(ProductDO.PORTFOLIO_PRODUCTS);
        }
        productDO.setTenant(LocalUser.getLocalUser().getTenant());
        this.baseMapper.insert(productDO);
        bathSaveShopAndBarcode(productDTO, productDO.getId());
    }

    @Override
    public IPage<ProductVO> pageList(ProductPage productPage) {
        if (!LocalUser.getLocalUser().getIsAdmin()) {
            // !root
            productPage.setTenant(LocalUser.getLocalUser().getTenant());
        }
        IPage<ProductVO> pageResult = null;
        Page page = new Page(productPage.getCurrPage(), productPage.getPageSize());
        if (productPage.getType().equals(ProductDO.ALONE_PRODUCTS.toString())) {
            pageResult = productMapper.pageList(page, productPage);
        } else if (productPage.getType().equals(ProductDO.PORTFOLIO_PRODUCTS.toString())) {
            pageResult = productMapper.pageList(page, productPage);
            encapsulation(pageResult);
        } else {
            productPage.setDeleteTime(new Date());
            pageResult = productMapper.pageList(page, productPage);
            encapsulation(pageResult);
        }
        if (CollectionUtils.isNotEmpty(pageResult.getRecords())) {
            encapsulationCategory(pageResult);
        }
        return pageResult;
    }

    @Override
    public Integer updateStatus(ProductDTO productDTO) {
        UpdateWrapper<ProductDO> uw = new UpdateWrapper<>();
        uw.lambda().set(ProductDO::getStatus, productDTO.getStatus()).set(BaseDO::getDeleteTime, null).in(ProductDO::getId, productDTO.getIds());
        return productMapper.update(null, uw);
    }

    @Transactional
    @Override
    public void update(ProductDTO productDTO) {
        // 检查sku
        Optional.ofNullable(productDTO).ifPresent(this::updateChechSkuExist);
        // 检查自定义条形码名称
        Optional.ofNullable(productDTO.getProductBarcodes()).ifPresent(this::checkFnSkuExist);
        ProductDO productDO = BeanUtils.copyProperties(productDTO, ProductDO.class);
        productMapper.updateProductById(productDO);
        productShopMapper.deleteByProductId(productDO.getId());
        productBarcodeMapper.deleteByProductId(productDO.getId());
        if (CollectionUtils.isNotEmpty(productDTO.getPortfolioProducts())) {
            portfolioProductsMapper.deleteByProductId(productDO.getId());
        }
        bathSaveShopAndBarcode(productDTO, productDO.getId());
    }

    @Override
    public void softDelete(List<Long> ids) {
        productMapper.deleteBatchIds(ids);
    }

    @Override
    public void delete(List<Long> ids) {
        productMapper.delById(ids);
    }

    @Override
    public Integer batchSetPackagMaterial(ProductDTO productDTO) {
        UpdateWrapper<ProductDO> uw = new UpdateWrapper<>();
        uw.lambda().set(ProductDO::getPackagMaterialId, productDTO.getPackagMaterialId())
                .set(ProductDO::getPackagType, 2)
                .set(ProductDO::getSinglePackagNum, null)
                .in(ProductDO::getId, productDTO.getIds());
        return productMapper.update(null, uw);
    }

    @Override
    public Integer batchSetAlarmThreshold(ProductDTO productDTO) {
        UpdateWrapper<ProductDO> uw = new UpdateWrapper<>();
        uw.lambda().set(ProductDO::getAlarmThreshold, productDTO.getAlarmThreshold()).in(ProductDO::getId, productDTO.getIds());
        return productMapper.update(null, uw);
    }

    @Override
    public void export(Integer type, HttpServletResponse response) throws IOException {
        List<ProductExecl> batchExcelSuccessList = new CopyOnWriteArrayList<>();
        List<ProductDO> productDOS = getExportData(type);
        Optional.ofNullable(productDOS).ifPresent(this::checkProductDOS);
        threadsHandle(batchExcelSuccessList, productDOS);
        ExportUtil.export(response, ProductExecl.class, batchExcelSuccessList);
    }

    @Override
    public void uploadImageZip(MultipartFile zipFile) throws IOException {
        Optional.ofNullable(zipFile).ifPresent(this::checkFileZip);
        List<MultipartFile> multipartFiles = UnPackeUtil.zip(zipFile);
        List<FileBO> upload = fileService.upload(multipartFiles);
        upload = upload.stream().peek(fileBO -> {
            String sku = fileBO.getKey().substring(0, fileBO.getKey().indexOf("."));
            fileBO.setKey(sku);
        }).collect(Collectors.toList());
        productMapper.batchUpdateUrl(upload);
    }

    @Override
    public List<ProductDO> findAllByAudit() {
        LambdaQueryWrapper<ProductDO> queryWrapper = Wrappers.lambdaQuery(ProductDO.class)
                .eq(ProductDO::getStatus, 2).eq(ProductDO::getIsDisable, true).isNull(ProductDO::getDeleteTime);
        if (!LocalUser.getLocalUser().getIsAdmin()) {
            // !root
            queryWrapper.eq(ProductDO::getTenant, LocalUser.getLocalUser().getTenant());
        }
        return this.baseMapper.selectList(queryWrapper);
    }

    @Transactional
    @Override
    public void batchSave(List<ProductDTO> productDTOS) {
        List<String> skus = productDTOS.
                stream().map(ProductDO::getSku).collect(Collectors.toList());
        Optional.ofNullable(skus).ifPresent(this::batchSaveCheckSkuExist);
        List<ProductDO> productDOS = productDTOS.stream()
                .map(productDTO -> BeanUtils.copyProperties(productDTO, ProductDO.class)).collect(Collectors.toList());
        this.saveBatch(productDOS);
        Map<String, List<ProductDTO>> maps = productDTOS.stream()
                .collect(Collectors.groupingBy(ProductDO::getSku));
        List<ProductShopDO> productShopDOS = new ArrayList<>();
        List<ProductBarcodeDO> productBarcodeDOS = new ArrayList<>();
        for (ProductDO productDO : productDOS) {
            List<ProductShopDO> shops = maps.get(productDO.getSku()).get(0).getShops();
            List<ProductBarcodeDO> barcodes = maps.get(productDO.getSku()).get(0).getProductBarcodes();
            if (!CollectionUtils.isEmpty(shops)) {
                List<ProductShopDO> collect = shops.stream()
                        .map(productShopDO -> productShopDO.setProductId(productDO.getId())).collect(Collectors.toList());
                productShopDOS.addAll(collect);
            }
            if (!CollectionUtils.isEmpty(barcodes)) {
                List<ProductBarcodeDO> collect = barcodes.stream()
                        .map(productBarcodeDO -> productBarcodeDO.setProductId(productDO.getId())).collect(Collectors.toList());
                productBarcodeDOS.addAll(collect);
            }
        }
        productShopService.saveBatch(productShopDOS);
        productBarcodeService.saveBatch(productBarcodeDOS);
    }


    @Override
    public void getBarCode(HttpServletResponse response, ProductDTO productDTO) {
        // 生成带文字描述的二维码pdf文件
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String name = "productPDF" + sdf.format(new Date());
        OutputStream toClient = null;
        try {
            FileOutputStream out = new FileOutputStream(name);
            LambdaQueryWrapper<ProductDO> queryWrapper = Wrappers.lambdaQuery(ProductDO.class)
                    .in(ProductDO::getId, productDTO.getIds());
            List<ProductDO> productDOS = this.baseMapper.selectList(queryWrapper);
            BarCodeEntity barCodeParam = getBarCodeParam(out, productDOS);
            BarCodeToPDF.createPDF1(barCodeParam);
            // 以byte流的方式打开文件
            FileInputStream hFile = new FileInputStream(name);
            // 得到文件大小
            int i = hFile.available();
            byte data[] = new byte[i];
            // 读数据
            hFile.read(data);
            hFile.close();
            response.reset();
            response.resetBuffer();
            // 设置返回的文件类型
            response.setContentType("application/pdf;charset-UTF-8");
            // 得到向客户端输出二进制数据的对象
            toClient = response.getOutputStream();
            // 输出数据
            toClient.write(data);
            File file = new File(name);
            file.delete();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                toClient.flush();
                toClient.close();
            } catch (Exception ex) {
            }
        }
    }


    @Override
    public void getBarCode(HttpServletResponse response, PrintBarcodeDTO printBarcodeDTO) {
        // 生成带文字描述的二维码pdf文件
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String name = "productPDF" + sdf.format(new Date());
        OutputStream toClient = null;
        try {
            FileOutputStream out = new FileOutputStream(name);
            BarCodeEntity barCodeParam = getBarCodeParam1(out, printBarcodeDTO);
            BarCodeToPDF.createPDF2(barCodeParam);
            // 以byte流的方式打开文件
            FileInputStream hFile = new FileInputStream(name);
            // 得到文件大小
            int i = hFile.available();
            byte data[] = new byte[i];
            // 读数据
            hFile.read(data);
            hFile.close();
            response.reset();
            response.resetBuffer();
            // 设置返回的文件类型
            response.setContentType("application/pdf;charset-UTF-8");
            // 得到向客户端输出二进制数据的对象
            toClient = response.getOutputStream();
            // 输出数据
            toClient.write(data);
            File file = new File(name);
            file.delete();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                toClient.flush();
                toClient.close();
            } catch (Exception ex) {
            }
        }
    }

    @Override
    public FindResultVO findAlarmThreshold() {
        LambdaQueryWrapper<ProductDO> queryWrapper = Wrappers.lambdaQuery(ProductDO.class);
        queryWrapper.eq(ProductDO::getIsDisable, true).eq(ProductDO::getStatus, 2);
        queryWrapper.le(ProductDO::getInventory, "alarm_threshold");
        List<ProductDO> products = this.list(queryWrapper);
        if (!LocalUser.getLocalUser().getIsAdmin()) {
            // !root
            queryWrapper.eq(ProductDO::getTenant, LocalUser.getLocalUser().getTenant());
        }
        return FindResultVO.success(products);
    }

    @Override
    public List<ProductDO> getListBySkus(List<String> skus) {
        QueryWrapper<ProductDO> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(ProductDO::getSku, skus);
        List<ProductDO> productDOList = this.list(wrapper);
        if (CollectionUtils.isEmpty(productDOList)) {
            throw new ForbiddenException(15010);
        }
        return productDOList;
    }

    @Override
    public int checkCountByProductIds(List<Long> productIds) {
        QueryWrapper<ProductDO> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(ProductDO::getId, productIds);
        return this.count(wrapper);
    }

    @Override
    public ProductVO findById(Long id) {
        ProductDO productDO = this.baseMapper.selectById(id);
        ProductVO productVO = BeanUtils.copyProperties(productDO, ProductVO.class);
        LambdaQueryWrapper<ProductBarcodeDO> queryWrapperBarcode = Wrappers.lambdaQuery(ProductBarcodeDO.class)
                .eq(ProductBarcodeDO::getProductId, id);
        productVO.setProductBarcodes(productBarcodeMapper.selectList(queryWrapperBarcode));
        LambdaQueryWrapper<ProductShopDO> queryWrapperShop = Wrappers.lambdaQuery(ProductShopDO.class)
                .eq(ProductShopDO::getProductId, id);
        productVO.setProductShops(productShopMapper.selectList(queryWrapperShop));
        LambdaQueryWrapper<PortfolioProductsDO> queryWrapperPortfolio = Wrappers.lambdaQuery(PortfolioProductsDO.class)
                .eq(PortfolioProductsDO::getProductId, id);
        List<PortfolioProductsDO> portfolioProducts = portfolioProductsMapper.selectList(queryWrapperPortfolio);
        if (CollectionUtils.isNotEmpty(portfolioProducts)) {
            List<Long> sonIds = portfolioProducts.stream()
                    .map(PortfolioProductsDO::getSonId).collect(Collectors.toList());
            LambdaQueryWrapper<ProductDO> proQueryWrapper = Wrappers.lambdaQuery(ProductDO.class)
                    .in(ProductDO::getId, sonIds);
            productVO.setProducts(this.baseMapper.selectList(proQueryWrapper));
        }
        // 查询品类
        FindResultVO result = wmsCategoryFeignClient.findParentId(productDO.getCategoryId().intValue());
        Optional.ofNullable(result.getCode()).ifPresent(this::checkCode);
        productVO.setCategoryIds((List<Integer>) result.getData());
        productVO.setPortfolioProducts(portfolioProducts);
        return productVO;
    }

    /**
     * 判断是否为zip
     *
     * @param zipFile
     */
    private void checkFileZip(MultipartFile zipFile) {
        if (zipFile == null) {
            throw new ForbiddenException(15005);
        }
        if (!zipFile.getOriginalFilename().endsWith(UnPackeUtil.ZIP_FILE)) {
            throw new ForbiddenException(15006);
        }
    }

    /**
     * 检测sku是否存在
     *
     * @param sku
     */
    private void checkSkuExist(String sku) {
        LambdaQueryWrapper<ProductDO> queryWrapper = Wrappers.lambdaQuery(ProductDO.class)
                .eq(ProductDO::getSku, sku);
        ProductDO one = getOne(queryWrapper);
        if (one != null) {
            throw new ForbiddenException(15000);
        }
    }

    /**
     * 批量导入检查sku
     *
     * @param skus
     */
    private void batchSaveCheckSkuExist(List<String> skus) {
        LambdaQueryWrapper<ProductDO> queryWrapper = Wrappers.lambdaQuery(ProductDO.class)
                .in(ProductDO::getSku, skus);
        List<ProductDO> productDOS = this.baseMapper.selectList(queryWrapper);
        if (!CollectionUtils.isEmpty(productDOS)) {
            String sku = productDOS.parallelStream().map(ProductDO::getSku).collect(Collectors.joining(","));
            throw new ForbiddenException(15000, sku + "已存在");
        }
    }

    /**
     * 修改时判断sku
     *
     * @param productDTO
     */
    private void updateChechSkuExist(ProductDTO productDTO) {
        LambdaQueryWrapper<ProductDO> queryWrapper = Wrappers.lambdaQuery(ProductDO.class)
                .eq(ProductDO::getSku, productDTO.getSku()).ne(ProductDO::getId, productDTO.getId());
        ProductDO one = getOne(queryWrapper);
        if (one != null) {
            throw new ForbiddenException(15000);
        }
    }

    /**
     * 检测自定义条形码是否重复
     *
     * @param productBarcodes
     */
    private void checkFnSkuExist(List<ProductBarcodeDO> productBarcodes) {
        Map<String, List<ProductBarcodeDO>> barcodeGroupByName = productBarcodes.stream()
                .collect(Collectors.groupingBy(ProductBarcodeDO::getCustomCodeName));
        barcodeGroupByName.forEach((k, v) -> {
            if (v.size() > 1) {
                throw new ForbiddenException(15001);
            }
        });
    }

    /**
     * 批量保存店铺和自定义码
     *
     * @param productDTO
     * @param id
     */
    private void bathSaveShopAndBarcode(ProductDTO productDTO, Long id) {
        if (CollectionUtils.isNotEmpty(productDTO.getPortfolioProducts())) {
            List<PortfolioProductsDO> collect = productDTO.getPortfolioProducts().stream()
                    .map(portfolioProductsDO -> portfolioProductsDO.setProductId(id)).collect(Collectors.toList());
            portfolioProductsService.saveBatch(collect);
        }
        if (CollectionUtils.isNotEmpty(productDTO.getShops())) {
            List<ProductShopDO> collect = productDTO.getShops().stream()
                    .map(productShopDO -> productShopDO.setProductId(id)).collect(Collectors.toList());
            productShopService.saveBatch(collect);
        }
        if (CollectionUtils.isNotEmpty(productDTO.getProductBarcodes())) {
            // 添加各种条形码
            List<ProductBarcodeDO> collect = productDTO.getProductBarcodes().stream()
                    .map(productBarcodeDO -> productBarcodeDO.setProductId(id)).collect(Collectors.toList());
            productBarcodeService.saveBatch(collect);
        }
    }

    /**
     * 多线程处理导出数据
     *
     * @param batchExcelSuccessList
     * @param productDOS
     */
    private void threadsHandle(List<ProductExecl> batchExcelSuccessList, List<ProductDO> productDOS) {
        // 一百条为基准为一个线程处理
        List<List<ProductDO>> groupList = CommonUtils.partition(productDOS, 100);
        CountDownLatch countDownLatch = new CountDownLatch(groupList.size());
        ExecutorService executorService = Executors.newFixedThreadPool(groupList.size());
        for (int i = 0; i < groupList.size(); i++) {
            int finalI = i;
            executorService.execute(() -> {
                List<ProductDO> productDOList = groupList.get(finalI);
                List<Long> productIds = productDOList.stream().map(ProductDO::getId).collect(Collectors.toList());
                // 根据产品id查询
                Map<Long, List<ProductBarcodeDO>> productBarcodeMap = getBarcodeGroupByProductIds(productIds);
                Map<Long, List<ProductShopDO>> productShopMap = getShopGroupByProductIds(productIds);
                for (ProductDO productDO : productDOList) {
                    List<ProductShopDO> productShops = productShopMap.get(productDO.getId());
                    List<ProductBarcodeDO> productBarcodes = productBarcodeMap.get(productDO.getId());
                    String shops = CollectionUtils.isNotEmpty(productShops) ? productShops.parallelStream()
                            .map(productShopDO -> productShopDO.getShopCode() + "#" + productShopDO.getShopSku())
                            .collect(Collectors.joining(",")) : null;
                    String barcode = CollectionUtils.isNotEmpty(productBarcodes) ? productBarcodes.parallelStream()
                            .map(productBarcodeDO -> productBarcodeDO.getCustomCodeName() + "#" + productBarcodeDO.getCustomCode())
                            .collect(Collectors.joining(",")) : null;
                    ProductExecl productExecl = BeanUtils.copyProperties(productDO, ProductExecl.class);
                    productExecl.setShops(shops);
                    productExecl.setBarcode(barcode);
                    batchExcelSuccessList.add(productExecl);
                }
                countDownLatch.countDown();
            });
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池
            executorService.shutdown();
        }
    }

    /**
     * 条形码所需参数
     *
     * @param out
     * @param productDOS
     * @return
     */
    private BarCodeEntity getBarCodeParam(FileOutputStream out, List<ProductDO> productDOS) {
        BarCodeEntity barCodeEntity = new BarCodeEntity();
        barCodeEntity.setFileOutputStream(out);
        barCodeEntity.setProducts(productDOS);
        // 生成条码
        barCodeEntity.setType(1);
        // barCodeEntity.setCodeSize(20);
        // barCodeEntity.setCodeHeight(50);
        // barCodeEntity.setCodeBaseline(30);
        barCodeEntity.setPageWidth(120);
        barCodeEntity.setPageHeight(65);
        barCodeEntity.setModuleSize(10);
        barCodeEntity.setAbsoluteX(10);
        barCodeEntity.setAbsoluteY(-49);
        // barCodeEntity.setWidth(0.75f);
        return barCodeEntity;
    }

    /**
     * 条形码所需参数
     *
     * @param out
     * @param printBarcode
     * @return
     */
    private BarCodeEntity getBarCodeParam1(FileOutputStream out, PrintBarcodeDTO printBarcode) {
        BarCodeEntity barCodeEntity = new BarCodeEntity();
        barCodeEntity.setFileOutputStream(out);
        List<Long> proIds = printBarcode.getProductNums()
                .stream().map(PrintBarcodeDTO.productNum::getId).collect(Collectors.toList());
        LambdaQueryWrapper<ProductDO> queryWrapper = Wrappers.lambdaQuery(ProductDO.class)
                .in(ProductDO::getId, proIds);
        List<ProductDO> productDOS = this.baseMapper.selectList(queryWrapper);
        barCodeEntity.setProducts(productDOS);
        barCodeEntity.setPrintBarcode(printBarcode);
        // 生成条码
        barCodeEntity.setType(1);
        // barCodeEntity.setCodeSize(20);
        // barCodeEntity.setCodeHeight(50);
        // barCodeEntity.setCodeBaseline(30);
        barCodeEntity.setPageWidth(printBarcode.getPageWidth());
        barCodeEntity.setPageHeight(printBarcode.getPageHeight());
        barCodeEntity.setModuleSize(10);
        // barCodeEntity.setAbsoluteX(25);
        // barCodeEntity.setAbsoluteY(-10);
        barCodeEntity.setAbsoluteX(38);
        barCodeEntity.setAbsoluteY(-5);

        barCodeEntity.setWidth(0.75f);
        return barCodeEntity;
    }

    /**
     * 根据产品ids获取产品自定义码
     *
     * @param productIds
     * @return
     */
    private Map<Long, List<ProductBarcodeDO>> getBarcodeGroupByProductIds(List<Long> productIds) {
        LambdaQueryWrapper<ProductBarcodeDO> queryWrapper = Wrappers.lambdaQuery(ProductBarcodeDO.class)
                .in(ProductBarcodeDO::getProductId, productIds);
        List<ProductBarcodeDO> productBarcodeDOS = productBarcodeMapper.selectList(queryWrapper);
        return productBarcodeDOS.stream()
                .collect(Collectors.groupingBy(ProductBarcodeDO::getProductId));
    }

    /**
     * 根据产品ids获取店铺
     *
     * @param productIds
     * @return
     */
    private Map<Long, List<ProductShopDO>> getShopGroupByProductIds(List<Long> productIds) {
        LambdaQueryWrapper<ProductShopDO> qwShop = Wrappers.lambdaQuery(ProductShopDO.class)
                .in(ProductShopDO::getProductId, productIds);
        List<ProductShopDO> productShopDOS = productShopMapper.selectList(qwShop);
        return productShopDOS.stream()
                .collect(Collectors.groupingBy(ProductShopDO::getProductId));
    }

    /**
     * 判断产品是否为空
     *
     * @param productDOS
     */
    private void checkProductDOS(List<ProductDO> productDOS) {
        if (CollectionUtils.isEmpty(productDOS)) {
            throw new ForbiddenException(15002);
        }
    }

    /**
     * 封装数据
     *
     * @param pageResult
     */
    private void encapsulation(IPage<ProductVO> pageResult) {
        List<Long> ids = new ArrayList<>();
        Map<Long, List<Long>> map = new HashMap<>();
        List<ProductVO> records = pageResult.getRecords();
        for (ProductVO record : records) {
            List<PortfolioProductsDO> portfolioProducts = record.getPortfolioProducts();
            if (CollectionUtils.isNotEmpty(portfolioProducts)) {
                List<Long> collect = portfolioProducts.stream()
                        .map(PortfolioProductsDO::getSonId).collect(Collectors.toList());
                ids.addAll(collect);
                map.put(record.getId(), collect);
            }
        }
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
        LambdaQueryWrapper<ProductDO> proQueryWrapper = Wrappers.lambdaQuery(ProductDO.class)
                .in(ProductDO::getId, ids);
        List<ProductDO> productDOS = productMapper.selectList(proQueryWrapper);
        Map<Long, List<ProductDO>> productMapGroupingById = productDOS
                .stream().collect(Collectors.groupingBy(BaseDO::getId));
        for (ProductVO record : pageResult.getRecords()) {
            List<Long> longs = map.get(record.getId());
            if (CollectionUtils.isNotEmpty(longs)) {
                for (Long aLong : longs) {
                    ProductDO productDO = productMapGroupingById.get(aLong).get(0);
                    CombinationProductVO combinationProductVO = BeanUtils.copyProperties(productDO, CombinationProductVO.class);
                    record.getChildren().add(combinationProductVO);
                }
            }
        }
    }

    /**
     * 封装品类数据
     *
     * @param pageResult
     */
    private void encapsulationCategory(IPage<ProductVO> pageResult) {
        List<ProductVO> records = pageResult.getRecords();
        List<Long> categoryIds = records.stream().map(ProductDO::getCategoryId).collect(Collectors.toList());
        FindResultVO result = wmsCategoryFeignClient.getByIds(categoryIds.stream().map(Long::intValue).collect(Collectors.toList()));
        Optional.ofNullable(result.getCode()).ifPresent(this::checkCode);
        List<Map<String, Object>> categoryMaps = (List<Map<String, Object>>) result.getData();
        Map<Long, List<Map<String, Object>>> categoryGroupingId = categoryMaps.stream().collect(Collectors.groupingBy(map1 -> MapUtils.getLong(map1, "id")));
        for (ProductVO record : records) {
            List<Map<String, Object>> maps = categoryGroupingId.get(record.getCategoryId());
            if (CollectionUtils.isNotEmpty(maps)) {
                record.setCategoryName(MapUtils.getString(maps.get(0), "category_name"));
            }
        }
    }

    /**
     * 判断code
     *
     * @param code
     */
    private void checkCode(Integer code) {
        if (!code.equals(ResponseEnum.SUCCESS.getCode())) {
            throw new ForbiddenException(9998);
        }
    }

    private List<ProductDO> getExportData(Integer type) {
        List<ProductDO> product = new ArrayList<>();
        if (type == 1) {
            LambdaQueryWrapper<ProductDO> queryWrapper = Wrappers.lambdaQuery(ProductDO.class)
                    .eq(ProductDO::getType, 1).eq(ProductDO::getIsDisable, true).isNull(ProductDO::getDeleteTime);
            product = this.baseMapper.selectList(queryWrapper);
        }
        if (type == 2) {
            LambdaQueryWrapper<ProductDO> queryWrapper = Wrappers.lambdaQuery(ProductDO.class)
                    .eq(ProductDO::getType, 2).eq(ProductDO::getIsDisable, true).isNull(ProductDO::getDeleteTime);
            product = this.baseMapper.selectList(queryWrapper);
        }
        if (type == 3) {
            product = productMapper.findDelAll();
        }
        return product;
    }
}
